#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <time.h>
#include <math.h>

#include "ncursNiveau.h"
/** @brief Cette fonction renvoie le maximum de deux réel
 * @param [in] a
 * @param [in] b
 * @return b si a < b sinon a*/
float max(float a, float b)
{
	if(a > b)
		return a;
	else
		return b;
}

/** @brief Cette procédure gere l'affichage de tout les elements du jeu en ncurses
 * @param [in_out] win
 * @param [in] dimX
 * @param [in] dimY
 * @param [in] pniveau*/
void ncursAff( WINDOW* win,int dimX, int dimY, const Niveau* pniveau)
{
	wclear(win);
	float deb_fenetre = pniveau->posY_debut_fenetre;
	float fin_fenetre = pniveau->posY_fin_fenetre;
	float coefX = (float)dimX/getDimX_terrain(niveauGetConstTerrainPtr(pniveau));
	float coefY = (float)dimY/(fin_fenetre-deb_fenetre);
	
	
	int x_heros, y_heros;
	int x_boss, y_boss;
	int i_ennemi, x_ennemi, y_ennemi;
	int i_tir, x_tir, y_tir;
	int i_bonus;
	
	const Terrain *pter = niveauGetConstTerrainPtr(pniveau);

	
	float posX_abs_ennemi;
	float tailleX_abs_ennemi;
	float posY_abs_ennemi;
	float tailleY_abs_ennemi;
	
	int posX_ncurse_ennemi;
	int tailleX_ncurse_ennemi;
	int posY_ncurse_ennemi;
	int tailleY_ncurse_ennemi;
	
	
	float posX_abs_tir;
	float tailleX_abs_tir;
	float posY_abs_tir;
	float tailleY_abs_tir;
	
	int posX_ncurse_tir;
	int tailleX_ncurse_tir;
	int posY_ncurse_tir;
	int tailleY_ncurse_tir;
	
	
	float posX_abs_bonus;
	float posY_abs_bonus;
	
	int posX_ncurse_bonus;
	int posY_ncurse_bonus;
	
	
	const Boss * pboss =  niveauGetConstBossPtr (pniveau);
	float posX_abs_boss = getPosXBoss(pboss);
	float tailleX_abs_boss = getTailleXBoss(pboss);
	float posY_abs_boss = getPosYBoss(pboss);
	float tailleY_abs_boss = getTailleYBoss(pboss);
	
	int posX_ncurse_boss;
	int posY_ncurse_boss;
	
	int tailleY_ncurse_boss;
	int tailleX_ncurse_boss;
	
	//transformation coordonnés/taille du héro d'absolu à Ncurses
	//On fera ensuite de même pour tout les autre élements (Boss, Ennemi, etc..)
	const Heros * phero =  niveauGetConstHerosPtr (pniveau);
	float coord_abs_posX_heros = getPosXHeros(phero);
	float tailleX_abs_heros = getTailleXHeros(phero);
	float coord_abs_posY_heros = getPosYHeros(phero);
	float tailleY_abs_heros = getTailleYHeros(phero);
	
	int coord_ncurse_posX_heros = (int)coord_abs_posX_heros*coefX;
	int coord_ncurse_posY_heros = (int)(coord_abs_posY_heros-deb_fenetre)*coefY;
	
	int tailleY_ncurse_heros = max(1,tailleY_abs_heros*coefY);
	int tailleX_ncurse_heros = max(1,tailleX_abs_heros*coefY);

	//remplir le terrain de "."
	int x,y;
	for(y=0;y<dimY;y++)
		for(x=0;x<dimX;x++)
			mvwprintw( win, y, x, ".");
	
	//afficher le héro
	for(y_heros=coord_ncurse_posY_heros;y_heros<coord_ncurse_posY_heros+tailleY_ncurse_heros;y_heros++)
		for(x_heros=coord_ncurse_posX_heros;x_heros<coord_ncurse_posX_heros+tailleX_ncurse_heros;x_heros++)
			mvwprintw(win, y_heros, x_heros, "H");
	

	//Si le Boss est à l'ecran l'afficher
	if ((posY_abs_boss >= pniveau->posY_debut_fenetre)
	 && (posY_abs_boss <= pniveau->posY_fin_fenetre)
	 && (posX_abs_boss >= 0)
	 && (posX_abs_boss <= getDimX_terrain(pter)))	
	{
		
		posX_ncurse_boss = (int)posX_abs_boss*coefX;
		posY_ncurse_boss = (int)(posY_abs_boss-deb_fenetre)*coefY;
		
		tailleY_ncurse_boss = max(1,tailleY_abs_boss*coefY);
		tailleX_ncurse_boss = max(1,tailleX_abs_boss*coefY);
		
		for(y_boss=posY_ncurse_boss;y_boss<posY_ncurse_boss+tailleY_ncurse_boss;y_boss++)
			for(x_boss=posX_ncurse_boss;x_boss<posX_ncurse_boss+tailleX_ncurse_boss;x_boss++)
				mvwprintw(win, y_boss, x_boss, "B");
	}
	
	
	//affichage de tout les ennemis
	for (i_ennemi=0; i_ennemi<pniveau->ptab_pennemis->nbre_ennemis; i_ennemi++)
	{
		posX_abs_ennemi=getPosXEnnemi(pniveau->ptab_pennemis->ptab_ennemis[i_ennemi]);
		tailleX_abs_ennemi=getTailleXEnnemi(pniveau->ptab_pennemis->ptab_ennemis[i_ennemi]);
		
		posY_abs_ennemi=getPosYEnnemi(pniveau->ptab_pennemis->ptab_ennemis[i_ennemi]);
		tailleY_abs_ennemi=getTailleYEnnemi(pniveau->ptab_pennemis->ptab_ennemis[i_ennemi]);
		
		if (  (posY_abs_ennemi >= pniveau->posY_debut_fenetre)
		   && (posY_abs_ennemi <= pniveau->posY_fin_fenetre)
		   && (posX_abs_ennemi >= 0)
		   && (posX_abs_ennemi <= getDimX_terrain(pter)) )
		{
			posX_ncurse_ennemi = (int)(posX_abs_ennemi*coefX);
			tailleX_ncurse_ennemi = max(1,(tailleX_abs_ennemi*coefX));
			
			posY_ncurse_ennemi = (int)((posY_abs_ennemi-deb_fenetre)*coefY);
			tailleY_ncurse_ennemi = max(1,(tailleY_abs_ennemi*coefY));
			
			for (y_ennemi=posY_ncurse_ennemi;
			     y_ennemi<(posY_ncurse_ennemi+tailleY_ncurse_ennemi);y_ennemi++)
			
				for (x_ennemi=posX_ncurse_ennemi;x_ennemi<(posX_ncurse_ennemi+tailleX_ncurse_ennemi);x_ennemi++)
        				mvwprintw( win, y_ennemi, x_ennemi, "E");
		}
	}

	//Affichage des Tir
	for (i_tir=0; i_tir<pniveau->ptab_ptirs->nbre_tirs; i_tir++)
	{

		posX_abs_tir=getPosXTir(pniveau->ptab_ptirs->ptab_tirs[i_tir]);
		tailleX_abs_tir=getTailleXTir(pniveau->ptab_ptirs->ptab_tirs[i_tir]);
		posY_abs_tir=getPosYTir(pniveau->ptab_ptirs->ptab_tirs[i_tir]);
		tailleY_abs_tir=getTailleYTir(pniveau->ptab_ptirs->ptab_tirs[i_tir]);
		
		if (  (posY_abs_tir >= pniveau->posY_debut_fenetre)
		   && (posY_abs_tir <= pniveau->posY_fin_fenetre)
		   && (posX_abs_tir >=0)
		   && (posX_abs_tir <= getDimX_terrain(pter)) )
		{
			
			posX_ncurse_tir = (int)(posX_abs_tir*coefX);
			tailleX_ncurse_tir = max(1,tailleX_abs_tir*coefX);
			
			posY_ncurse_tir = (int)((posY_abs_tir-deb_fenetre)*coefY);
			tailleY_ncurse_tir = max(1,tailleY_abs_tir*coefY);
			
			if (pniveau->ptab_ptirs->ptab_tirs[i_tir]->tir_ami == 1) 	/*le tir vient de l'ennemi*/
			{
				for (y_tir=posY_ncurse_tir;y_tir<(posY_ncurse_tir+tailleY_ncurse_tir);y_tir++)
			
					for (x_tir=posX_ncurse_tir;x_tir<(posX_ncurse_tir+tailleX_ncurse_tir);x_tir++)
					
						mvwprintw( win, y_tir, x_tir, "o");
			}
			else  if (pniveau->ptab_ptirs->ptab_tirs[i_tir]->tir_ami == 0) 	/*le tir vient du heros*/
				{
					for (y_tir=posY_ncurse_tir;y_tir<(posY_ncurse_tir+tailleY_ncurse_tir);y_tir++)
			
						for (x_tir=posX_ncurse_tir;x_tir<(posX_ncurse_tir+tailleX_ncurse_tir);x_tir++)
					
							mvwprintw( win, y_tir, x_tir, "O");
				}
		}
	}
	  
	  
	for (i_bonus=0; i_bonus<pniveau->ptab_pbonus->nbre_bonus; i_bonus++)
	{
		posX_abs_bonus=getPosXBonus(pniveau->ptab_pbonus->ptab_bonus[i_bonus]);
		posY_abs_bonus=getPosYBonus(pniveau->ptab_pbonus->ptab_bonus[i_bonus]);
		
		if (  posY_abs_bonus >= pniveau->posY_debut_fenetre
		   && posY_abs_bonus <= pniveau->posY_fin_fenetre
		   && posX_abs_bonus >=0
		   && posX_abs_bonus <= getDimX_terrain(pter))
		{
			posX_ncurse_bonus = (int)(posX_abs_bonus*coefX);
			posY_ncurse_bonus = (int)((posY_abs_bonus-deb_fenetre)*coefY);
			
			mvwprintw( win, posY_ncurse_bonus , posX_ncurse_bonus, "B");
		}
	}
	
	mvwprintw( win, 0, dimX+2, "Vie: %d", getVieHeros(phero) );
	mvwprintw( win, 2, dimX+2, "Missiles: %d Nuke: %d", getMunitions(getArmeSecondaire1(phero)), getMunitions(getArmeSecondaire2(phero)) );
	
	wmove( win, coord_ncurse_posY_heros, coord_ncurse_posX_heros); //Pour que le curseur clignote sur le héro (plus agréable)
}

void ncursBoucle(Niveau* pniveau)
{
	WINDOW *win, *screen;
	int dimX = 100;
	int dimY = 35;
	int c;
	int continue_boucle;

	 /* Horloges (en secondes) */
	float horloge_courante, horloge_precedente;

    /* Intervalle de temps (en secondes) entre deux évolutions du jeu */
    /* Changer la valeur pour ralentir ou accélérer le déroulement du jeu */
	float intervalle_horloge = 0.1f;
	screen = initscr();		/* passe l'écran texte en mode NCurses */
	clear();		/* efface l'écran */
	noecho();  	/* Lorsqu'une touche est préssée au clavier, elle n'apparait pas à l'écran */
	cbreak();		/* un caractère est directement affiché, il ne passe pas dans un buffer */

	/* Creation d'une nouvelle fenetre en mode texte */
	/* => fenetre de dimension et position ( WIDTH, HEIGHT, STARTX,STARTY) */
	win = newwin( dimY, dimX+200, 1, 1 );
	keypad(win, TRUE);		/* pour que les flèches soient traitées (il faut le faire après création de la fenêtre) */

	/*halfdelay(temps_dizieme);*/
	/* notimeout(win,true); */
	/* wtimeout( win, 500 ); */
	nodelay(win,true); /* Pour que l'appel à wgetch soit non-bloquant */

	continue_boucle = 1;

	/* Récupère l'horloge actuelle et la convertit en secondes */
	/* clock() retourne le nombre de tops horloge depuis le lancement du programme */
	horloge_precedente = (float)clock()/(float)CLOCKS_PER_SEC;

	ncursAff( win,dimX, dimY, pniveau);
	do
	{
		/* Récupère l'horloge actuelle et la convertit en secondes */
		/* clock() retourne le nombre de tops horloge depuis le lancement du programme */
		horloge_courante = (float)clock()/(float)CLOCKS_PER_SEC;
	
		if (horloge_courante-horloge_precedente>intervalle_horloge)
		{
			niveauEvolution (pniveau);
		
			ncursAff( win,dimX, dimY, pniveau);
			
			//Ce qu'il y entre commentaire était pour débugger au début
			/*mvwprintw( win, 0, dimX+2, "posX: %.1f posY: %.1f nombre d'ennemis: %d  nombre de tirs: %d", niveauGetConstHerosPtr (pniveau)->posX_heros, 
									niveauGetConstHerosPtr (pniveau)->posY_heros,
									 pniveau->ptab_pennemis->nbre_ennemis,
									pniveau->ptab_ptirs->nbre_tirs);
			
		
			mvwprintw( win, 2, dimX+2, "fenetre debut: %f fin: %f", pniveau->posY_debut_fenetre,
									pniveau->posY_fin_fenetre);
			if(pniveau->ptab_pennemis->ptab_ennemis[0]!=NULL)
			{
				mvwprintw( win, 4, dimX+2, "pointeur 1er ennemi: %p", pniveau->ptab_pennemis->ptab_ennemis[0]);
				mvwprintw( win, 5, dimX+2, "PosX premier ennemis: %.1f", getPosXEnnemi(pniveau->ptab_pennemis->ptab_ennemis[0]));
				mvwprintw( win, 6, dimX+2, "PosY premier ennemis: %.1f", getPosYEnnemi(pniveau->ptab_pennemis->ptab_ennemis[0]));
				mvwprintw( win, 7, dimX+2, "Collision 1eme ennemis: %d", collisionHerosEnnemi(niveauGetConstHerosPtr(pniveau),
						pniveau->ptab_pennemis->ptab_ennemis[0]));
			}
		
			if(pniveau->ptab_pennemis->ptab_ennemis[1]!=NULL)
			{
				mvwprintw( win, 9, dimX+2, "pointeur 2eme ennemi: %p", pniveau->ptab_pennemis->ptab_ennemis[1]);
				mvwprintw( win, 10, dimX+2, "PosX 2eme ennemis: %.1f", getPosXEnnemi(pniveau->ptab_pennemis->ptab_ennemis[1]));
				mvwprintw( win, 11, dimX+2, "PosY 2eme ennemis: %.1f", getPosYEnnemi(pniveau->ptab_pennemis->ptab_ennemis[1]));
				mvwprintw( win, 12, dimX+2, "Collision 2eme ennemis: %d", collisionHerosEnnemi(niveauGetConstHerosPtr(pniveau),
							pniveau->ptab_pennemis->ptab_ennemis[1]));
			}
		
			if(pniveau->ptab_pennemis->ptab_ennemis[2]!=NULL)
			{
				mvwprintw( win, 14, dimX+2, "pointeur 3eme ennemi: %p", pniveau->ptab_pennemis->ptab_ennemis[2]);
				mvwprintw( win, 15, dimX+2, "PosX 3eme ennemis: %.1f", getPosXEnnemi(pniveau->ptab_pennemis->ptab_ennemis[2]));
				mvwprintw( win, 16, dimX+2, "PosY 3eme ennemis: %.1f", getPosYEnnemi(pniveau->ptab_pennemis->ptab_ennemis[2]));
				mvwprintw( win, 17, dimX+2, "Collision 3eme ennemis: %d", collisionHerosEnnemi(niveauGetConstHerosPtr(pniveau),
							pniveau->ptab_pennemis->ptab_ennemis[2]));
			}
		
			mvwprintw( win, 19, dimX+2, "nombre de vie: %d,posY:%f", getVieHeros(niveauGetConstHerosPtr(pniveau)),pniveau->phero->posY_heros);
			wmove( win, getPosYHeros(niveauGetConstHerosPtr(pniveau)), getPosXHeros(niveauGetConstHerosPtr(pniveau)));*/
			horloge_precedente = horloge_courante;
		}


		c = wgetch(win);
		switch(c)
		{
			case KEY_LEFT:	//aller à gauche
				niveauActionClavierSouris( pniveau, 'g');
				ncursAff( win,dimX, dimY, pniveau);
				break;
			case KEY_RIGHT:	//aller à droite
				niveauActionClavierSouris( pniveau, 'd');
				ncursAff( win,dimX, dimY, pniveau);
				break;
			case KEY_UP:	//monter
				niveauActionClavierSouris( pniveau, 'h');
				ncursAff( win,dimX, dimY, pniveau);
				break;
			case KEY_DOWN:	//descendre
				niveauActionClavierSouris( pniveau, 'b');
				ncursAff( win,dimX, dimY, pniveau);
				break;
				
			case  KEY_BACKSPACE  : 	//tir principal
				niveauActionClavierSouris( pniveau, 't');
				ncursAff( win,dimX, dimY, pniveau);
				break;
			
			case  KEY_ENTER  : 	//missile
				niveauActionClavierSouris( pniveau, 'm');
				ncursAff( win,dimX, dimY, pniveau);
				
			case  KEY_F(2)  : 	//nuke
				niveauActionClavierSouris( pniveau, 'o');
				ncursAff( win,dimX, dimY, pniveau);
				break;
				
			case 27: /* ECHAP */
				continue_boucle = 0;
				break;
		}
	} while (continue_boucle==1);

	assert(delwin(win)!=ERR);
	assert(delwin(screen)!=ERR);

	endwin();
}
